﻿using WebApp.DAL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace WebApp.BLL.Base
{
    public abstract class BaseService<T> where T : class
    {
        public BaseRepository<T> CurrentRepository { get; set; }

        public BaseService(BaseRepository<T> currentRepository) { CurrentRepository = currentRepository; }

        public T Add(T entity) { return CurrentRepository.Add(entity); }

        public bool Update(T entity) { return CurrentRepository.Update(entity); }

        /// <summary>
        /// 物理删除数据
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public bool Delete(T entity) { return CurrentRepository.Delete(entity); }
        
        public T Find(int ID) { return CurrentRepository.Find(ID); }

        public IQueryable<T> PageList(IQueryable<T> entitys, int pageIndex, int pageSize)
        {
            return entitys.Skip((pageIndex - 1) * pageSize).Take(pageSize);
        }

        public IList<T> List()
        {
            return CurrentRepository.Entities.ToList();
        }

        /// <summary>
        /// 根据属性名对结果进行排序
        /// </summary>
        /// <param name="entitys"></param>
        /// <param name="orderby"></param>
        /// <param name="ascending"></param>
        /// <returns></returns>
        public IQueryable<T> SortList(IQueryable<T> entitys, string propertyname, bool ascending = true)
        {
            Type type = typeof(T);

            PropertyInfo property = type.GetProperty(propertyname);
            if (property == null)
                throw new ArgumentException("propertyName", "Not Exist");

            ParameterExpression param = Expression.Parameter(type, "p");
            Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
            LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);

            string methodName = ascending ? "OrderBy" : "OrderByDescending";

            MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName, new Type[] { type, property.PropertyType }, entitys.Expression, Expression.Quote(orderByExpression));

            return entitys.Provider.CreateQuery<T>(resultExp);
        }

        public IQueryable<T> SortList(IQueryable<T> entitys, string[] propertyname, bool[] ascending)
        {
            Type type = typeof(T);

            for (int i = 0; i < propertyname.Length; i++)
            {
                PropertyInfo property = type.GetProperty(propertyname[i]);
                if (property == null)
                    throw new ArgumentException("propertyName", "Not Exist");

                ParameterExpression param = Expression.Parameter(type, "p");
                Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
                LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);

                string methodName = ascending[0] ? "OrderBy" : "OrderByDescending";
                if (i > 0)
                {
                    methodName = ascending[i] ? "ThenBy" : "ThenByDescending";
                }

                MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName, new Type[] { type, property.PropertyType }, entitys.Expression, Expression.Quote(orderByExpression));

                entitys = entitys.Provider.CreateQuery<T>(resultExp);
            }

            return entitys;
        }

        public IQueryable<TElement> SortList<TElement>(IQueryable<TElement> entitys, string propertyname, bool ascending = true)
        {
            Type type = typeof(TElement);

            PropertyInfo property = type.GetProperty(propertyname);
            if (property == null)
                throw new ArgumentException("propertyName", "Not Exist");

            ParameterExpression param = Expression.Parameter(type, "p");
            Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
            LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);

            string methodName = ascending ? "OrderBy" : "OrderByDescending";

            MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName, new Type[] { type, property.PropertyType }, entitys.Expression, Expression.Quote(orderByExpression));

            return entitys.Provider.CreateQuery<TElement>(resultExp);
        }
    }
}
